﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

#endregion

namespace ScrumTable.Common.Collections
{
    /// <summary>
    /// Contains the global utilities for the Collection class.
    /// </summary>
    public static class CollectionUtil
    {
        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Releases a collection of references.
        /// </summary>
        /// <param name="toRelease">Specifies the reference to release.</param>
        public static void ReleaseReference<T>(ref Collection<T> toRelease)
        {
            if (toRelease != null) { toRelease.Clear(); }

            object stackPtrToRelease = toRelease; // copy ref to stack
            ObjectUtil.ReleaseReference(ref stackPtrToRelease);

            toRelease = null;
        }

        /// <summary>
        /// Gets the index of the element which is found with the given comparator.
        /// collection.
        /// </summary>
        /// <param name="thisPtr">Specifies the collection instance.</param>
        /// <param name="comparator">Specifies the comparator which is used to evaluate the element to search.</param>
        public static int IndexOf<T>(this ICollection<T> thisPtr, Predicate<T> comparator)
        {
            int idx = 0;
            foreach (T element in thisPtr)
            {
                if (comparator(element))
                    return idx;
                idx++;
            }
            return -1;
        }

        /// <summary>
        /// Concatenates all the elements of the given collection, using the specified separator between each element.
        /// </summary>
        /// <param name="thisPtr">Specifies the collection instance.</param>
        /// <param name="toStringFunc">Specifies the toString function which is called for each element.</param>
        /// <param name="separatorFunc">Specifies the separator function which is called between the elemente.</param>
        public static string Join<T>(this ICollection<T> thisPtr, Func<T, string> toStringFunc, Func<string> separatorFunc)
        {
            PreCondition.AssertNotNull(thisPtr, "thisPtr");
            PreCondition.AssertNotNull(toStringFunc, "toStringFunc");
            PreCondition.AssertNotNull(separatorFunc, "separatorFunc");

            StringBuilder dataBuilder = new StringBuilder();

            int idx = 0;
            foreach (T element in thisPtr)
            {
                dataBuilder.Append(toStringFunc(element));

                if (thisPtr.Count != idx + 1)
                    dataBuilder.Append(separatorFunc());

                idx++;
            }
            return dataBuilder.ToString();
        }

        /// <summary>
        /// Adds items to the ICollection. 
        /// </summary>
        /// <param name="thisPtr">Specifies the collection instance.</param>
        /// <param name="toAdd">Adds the elements of the given instance into the this pointer.</param>
        public static void Add<T>(this ICollection<T> thisPtr, IEnumerable<T> toAdd)
        {
            PreCondition.AssertNotNull(thisPtr, "thisPtr");

            thisPtr.Add(toAdd, val => val);
        }

        /// <summary>
        /// Adds items to the ICollection. 
        /// </summary>
        /// <param name="thisPtr">Specifies the collection instance.</param>
        /// <param name="toAdd">Adds the elements of the given instance into the this pointer.</param>
        /// <param name="converter">Converts an element of type TIn into an element of TOut.</param>
        public static void Add<TOut, TIn>(this ICollection<TOut> thisPtr, IEnumerable<TIn> toAdd, Func<TIn, TOut> converter)
        {
            PreCondition.AssertNotNull(thisPtr, "thisPtr");
            PreCondition.AssertNotNull(converter, "converter");

            if (toAdd != null)
            {
                foreach (var elementToAdd in toAdd)
                {
                    thisPtr.Add(converter(elementToAdd));
                }
            }
        }

        #endregion
    }
}
